package com.zjrb.netty.handle;

import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.stream.ChunkedNioFile;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class HttpServerHandleAdapter extends SimpleChannelInboundHandler<FullHttpRequest> {

    private static final Logger logger = LoggerFactory.getLogger(HttpServerHandleAdapter.class);

    // 资源所在路径
    private static final String location = "D:" + File.separator + "html" + File.separator;
    private static final String DOMAIN_PATH = "D:\\html\\domain.txt";
    // 404文件页面地址
    private static final File NOT_FOUND;

    public static final Map<String, String> DOMAIN_TEMPLATE = new HashMap<>();

    static {
        try {
            List<String> domains = FileUtils.readLines(new File(DOMAIN_PATH), "UTF-8");
            domains.forEach(x -> {
                String[] lines = x.split("\t");
                DOMAIN_TEMPLATE.put(lines[0].trim(), lines[1].trim());
            });
            logger.info("init domain success {} ", domains.size());

        } catch (IOException e) {
            logger.error("init domains error {}", e);
        }
        // 构建404页面
        String path = location + File.separator + "404.html";
        NOT_FOUND = new File(path);
    }


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {

        HttpHeaders header = request.headers();//获取Netty内置的请求头对象
        String host = header.get("Host");
        String template = DOMAIN_TEMPLATE.get(host);
        // 获取URI
        String uri = request.getUri();

        logger.info("{} {}", host, uri);

        // 设置不支持favicon.ico文件
        if ("favicon.ico".equals(uri)) {
            return;
        }
        // 根据路径地址构建文件
        String path = location + template + uri;
        File html = new File(path);

        // 状态为1xx的话，继续请求
        if (HttpHeaders.is100ContinueExpected(request)) {
            send100Continue(ctx);
        }

        // 当文件不存在的时候，将资源指向NOT_FOUND
        if (!html.exists()) {
            System.out.println(html.getPath());
            html = NOT_FOUND;
        }


        String navPath = String.format("%snav/%s.html", location, host);
        String footPath = String.format("%sfoot/%s.html", location, host);
        RandomAccessFile navFile = new RandomAccessFile(navPath, "r");
        RandomAccessFile file = new RandomAccessFile(html, "r");
        RandomAccessFile footFile = new RandomAccessFile(footPath, "r");

        Long fileLength=navFile.length()+file.length()+footFile.length();


        HttpResponse response = new DefaultHttpResponse(request.getProtocolVersion(), HttpResponseStatus.OK);

        // 文件没有发现设置状态为404
        if (html == NOT_FOUND) {
            response.setStatus(HttpResponseStatus.NOT_FOUND);
        }

        // 设置文件格式内容
        if (path.endsWith(".html")) {
            response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/html; charset=UTF-8");
        } else if (path.endsWith(".js")) {
            response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "application/x-javascript");
        } else if (path.endsWith(".css")) {
            response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/css; charset=UTF-8");
        }

        boolean keepAlive = HttpHeaders.isKeepAlive(request);

        if (keepAlive) {
            response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, fileLength);
            response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
        }
        ctx.write(response);

        if (ctx.pipeline().get(SslHandler.class) == null) {
            ctx.write(new DefaultFileRegion(navFile.getChannel(), 0, navFile.length()));
            ctx.write(new DefaultFileRegion(file.getChannel(), 0, file.length()));
            ctx.write(new DefaultFileRegion(footFile.getChannel(), 0, footFile.length()));
        } else {
            ctx.write(new ChunkedNioFile(navFile.getChannel()));
            ctx.write(new ChunkedNioFile(file.getChannel()));
            ctx.write(new ChunkedNioFile(footFile.getChannel()));
        }
        // 写入文件尾部
        ChannelFuture future = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
        if (!keepAlive) {
            future.addListener(ChannelFutureListener.CLOSE);
        }
        navFile.close();
        file.close();
        footFile.close();
    }

    private static void send100Continue(ChannelHandlerContext ctx) {
        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE);
        ctx.writeAndFlush(response);
    }
}